﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Marmat.Forms.Skin
{
    /// <summary>
    /// 表示 System.Windows.Forms.TreeNode 对象集合。
    /// </summary>
    [Editor("System.Windows.Forms.Design.TreeNodeCollectionEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
    public class TreeNodeCollection : IList, ICollection, IEnumerable
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private readonly List<TreeNode> collection = new List<TreeNode>();

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal TreeNode parent;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal TreeView treeView;
       
        /// <summary>
        /// 从集合中获取具有指定键的树节点。
        /// </summary>
        /// <param name="key">名称 System.Windows.Forms.TreeNode 若要从集合中检索。</param>
        /// <returns>具有指定键的 System.Windows.Forms.TreeNode。</returns>
        public virtual TreeNode this[string key]
        {
            get => this.collection.FirstOrDefault(x => x.Name == key);
        }

        /// <summary>
        /// 获取或设置 System.Windows.Forms.TreeNode 指定索引处的集合中的位置。
        /// </summary>
        /// <param name="index">索引的位置 System.Windows.Forms.TreeNode 集合中。</param>
        /// <returns>System.Windows.Forms.TreeNode 指定索引处的集合中的位置。</returns>
        public virtual TreeNode this[int index]
        {
            get => this.collection[index];
            set
            {
                if (value is null)
                    this.Remove(this[index]);
                else
                {
                    this.collection[index] = value;
                    value.parentCollection = this;
                }
            }
        }

        object IList.this[int index] { get => this[index]; set => this[index] = (TreeNode)value; }

        /// <summary>
        /// 获取一个值，该值指示集合是否为只读。
        /// </summary>
        /// <returns>如果该集合为只读，则为 true；否则为 false。 默认值为 false。</returns>
        public bool IsReadOnly
        {
            get => false;
        }

        /// <summary>
        /// 获取的总数 System.Windows.Forms.TreeNode 集合中的对象。
        /// </summary>
        /// <returns>总次数 System.Windows.Forms.TreeNode 集合中的对象。</returns>
        [Browsable(false)]
        public int Count { get => this.collection.Count; }

        bool IList.IsFixedSize => false;

        object ICollection.SyncRoot => true;

        bool ICollection.IsSynchronized => true;

        /// <summary>
        /// 将先前创建的树节点添加到树节点集合的末尾。
        /// </summary>
        /// <param name="node">要添加到集合中的 System.Windows.Forms.TreeNode。</param>
        /// <returns>从零开始的索引值 System.Windows.Forms.TreeNode 添加到树节点集合。</returns>
        public virtual int Add(TreeNode node)
        {
            this.collection.Add(node);
            node.parentCollection = this;
            if (node.nodes is not null)
                node.nodes.treeView = this.treeView;
            this.treeView?.Invalidate();
            return this.Count;
        }

        /// <summary>
        /// 当前的树节点集合的末尾添加新的树节点与指定的标签文本。
        /// </summary>
        /// <param name="text">显示的标签文本 System.Windows.Forms.TreeNode。</param>
        /// <returns>一个 System.Windows.Forms.TreeNode 表示添加到集合中的树节点。</returns>
        public virtual TreeNode Add(string text)
        {
            TreeNode node = new TreeNode(text);
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像的树节点并将其添加到集合。
        /// </summary>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageIndex">若要在树节点中显示的图像的索引。</param>
        /// <param name="selectedImageIndex">若要为选定状态时，树节点中显示的图像的索引。</param>
        /// <returns></returns>
        public virtual TreeNode Add(string key, string text, int imageIndex, int selectedImageIndex)
        {
            TreeNode node = new TreeNode(text, imageIndex, selectedImageIndex);
            node.Name = key;
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键和文本，新的树节点并将其添加到集合。
        /// </summary>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <returns> System.Windows.Forms.TreeNode 已添加到集合。</returns>
        public virtual TreeNode Add(string key, string text)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像，树节点并将其添加到集合。
        /// </summary>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageKey">要在树节点中显示的图像。</param>
        /// <returns>System.Windows.Forms.TreeNode 已添加到集合。</returns>
        public virtual TreeNode Add(string key, string text, string imageKey)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageKey = imageKey;
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像，树节点并将其添加到集合。
        /// </summary>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageIndex">若要在树节点中显示的图像的索引。</param>
        /// <returns>System.Windows.Forms.TreeNode 已添加到集合。</returns>
        public virtual TreeNode Add(string key, string text, int imageIndex)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageIndex = imageIndex;
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像的树节点并将其添加到集合。
        /// </summary>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageKey">若要在树节点中显示的图像的键。</param>
        /// <param name="selectedImageKey">当节点处于选定状态时要显示的图像的键。</param>
        /// <returns>System.Windows.Forms.TreeNode 已添加到集合。</returns>
        public virtual TreeNode Add(string key, string text, string imageKey, string selectedImageKey)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageKey = imageKey;
            node.SelectedImageKey = selectedImageKey;
            this.Add(node);
            return node;
        }

        /// <summary>
        /// 向集合添加先前创建的树节点的数组。
        /// </summary>
        /// <param name="nodes">一个数组 System.Windows.Forms.TreeNode 对象表示要添加到集合的树节点。</param>
        public virtual void AddRange(TreeNode[] nodes)
        {
            this.collection.AddRange(nodes);
            foreach (var node in nodes)
            {
                node.parentCollection = this;
                if (node.nodes is not null)
                    node.nodes.treeView = this.treeView;
            }
            this.treeView?.Invalidate();
        }

        /// <summary>
        /// 从集合中移除所有树节点。
        /// </summary>
        public virtual void Clear()
        {
            foreach (var node in this.collection)
            {
                node.parentCollection = null;
            }
            this.collection.Clear();
        }

        /// <summary>
        /// 确定指定的树节点是否是集合的成员。
        /// </summary>
        /// <param name="node">System.Windows.Forms.TreeNode 要在集合中查找。</param>
        /// <returns>true 如果 System.Windows.Forms.TreeNode 是集合的成员; 否则为 false。</returns>
        public bool Contains(TreeNode node)
        {
            return this.collection.Contains(node);
        }

        /// <summary>
        /// 确定集合是否包含具有指定键的树节点。
        /// </summary>
        /// <param name="key">要搜索的 System.Windows.Forms.TreeNode 的名称。</param>
        /// <returns>true 若要指示该集合包含 System.Windows.Forms.TreeNode 具有指定键; 否则为 false。</returns>
        public virtual bool ContainsKey(string key)
        {
            return this.collection.Exists(x => x.Name == key);
        }

        ///// <summary>
        ///// 将整个集合复制到现有数组中在该数组中指定的位置。
        ///// </summary>
        ///// <param name="dest">目标数组。</param>
        ///// <param name="index">它的目标数组中开始的索引。</param>
        //public void CopyTo(Array dest, int index)
        //{

        //}

        /// <summary>
        /// 查找具有指定键，也可以选择搜索的子节点的树节点。
        /// </summary>
        /// <param name="key">要搜索的树节点的名称。</param>
        /// <param name="searchAllChildren">true 若要搜索的树节点，则子节点否则为 false。</param>
        /// <returns>一个数组 System.Windows.Forms.TreeNode 对象其 System.Windows.Forms.TreeNode.Name 属性指定的键相匹配。</returns>
        public TreeNode[] Find(string key, bool searchAllChildren)
        {
            List<TreeNode> nodes = new List<TreeNode>();
            foreach (var node in collection)
            {
                if (node.Name == key)
                    nodes.Add(node);
                if (searchAllChildren)
                    Find(node.Nodes);
            }

            void Find(TreeNodeCollection collection)
            {
                foreach (TreeNode node in collection)
                {
                    if (node.Name == key)
                        nodes.Add(node);
                }
            }
            return nodes.ToArray();
        }

        /// <summary>
        /// 返回可用于循环访问树节点集合的枚举。
        /// </summary>
        /// <returns>System.Collections.IEnumerator 表示树节点集合。</returns>
        public IEnumerator GetEnumerator()
        {
            return this.collection.GetEnumerator();
        }

        /// <summary>
        /// 返回集合中指定的树节点的索引。
        /// </summary>
        /// <param name="node">要在集合中查找的 System.Windows.Forms.TreeNode。</param>
        /// <returns>在树节点集合; 中找到的项的从零开始的索引否则为-1。</returns>
        public int IndexOf(TreeNode node)
        {
            return this.collection.IndexOf(node);
        }

        /// <summary>
        /// 返回具有指定键的树节点中的第一个匹配项的索引。
        /// </summary>
        /// <param name="key">要搜索的树节点的名称。</param>
        /// <returns>具有指定键的树节点的第一个匹配项的从零开始索引如果找到，则否则为-1。</returns>
        public virtual int IndexOfKey(string key)
        {
            return this.collection.FindIndex(x => x.Name == key);
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像，树节点并将其插入集合中的指定索引处。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageKey">若要在树节点中显示的图像的键。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string key, string text, string imageKey)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageKey = imageKey;
            this.Insert(index, node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像的树节点并将其插入集合中的指定索引处。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageIndex">若要在树节点中显示的图像的索引。</param>
        /// <param name="selectedImageIndex">要为选定状态时，树节点中显示的图像的索引。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string key, string text, int imageIndex, int selectedImageIndex)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageIndex = imageIndex;
            node.SelectedImageIndex = selectedImageIndex;
            this.Insert(index, node);
            return node;
        }

        /// <summary>
        /// 创建具有指定的键、 文本和图像，树节点并将其插入集合中的指定索引处。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageIndex">若要在树节点中显示的图像的索引。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string key, string text, int imageIndex)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageIndex = imageIndex;
            this.Insert(index, node);
            return node;
        }

        /// <summary>
        /// 使用指定的文本和密钥，创建的树节点并将其插入到集合。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string key, string text)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            this.Insert(index, node);
            return node;
        }

        /// <summary>
        /// 将现有的树节点插入到树节点集合中指定的位置。
        /// </summary>
        /// <param name="index">要插入的树节点的集合中的索引的位置。</param>
        /// <param name="node">System.Windows.Forms.TreeNode 要插入到集合。</param>
        public virtual void Insert(int index, TreeNode node)
        {
            this.collection.Insert(index, node);
            node.parentCollection = this;
        }


        /// <summary>
        /// 创建具有指定的键、 文本和图像的树节点并将其插入集合中的指定索引处。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="key">树节点的名称。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <param name="imageKey">若要在树节点中显示的图像的键。</param>
        /// <param name="selectedImageKey">要为选定状态时，树节点中显示的图像的键。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string key, string text, string imageKey, string selectedImageKey)
        {
            TreeNode node = new TreeNode(text);
            node.Name = key;
            node.ImageKey = imageKey;
            node.SelectedImageKey = selectedImageKey;
            this.Insert(index, node);
            return node;
        }


        /// <summary>
        /// 创建具有指定文本的树节点并将其插入指定索引处。
        /// </summary>
        /// <param name="index">要插入节点的集合中的位置。</param>
        /// <param name="text">要在树节点中显示的文本。</param>
        /// <returns>System.Windows.Forms.TreeNode 已插入集合中。</returns>
        public virtual TreeNode Insert(int index, string text)
        {
            TreeNode node = new TreeNode(text);
            this.Insert(index, node);
            return node;
        }

        /// <summary>
        /// 从树节点集合中移除指定的树节点。
        /// </summary>
        /// <param name="node">要移除的 System.Windows.Forms.TreeNode。</param>
        public void Remove(TreeNode node)
        {
            this.collection.Remove(node);
        }

        /// <summary>
        /// 从指定索引处的树节点集合中移除的树节点。
        /// </summary>
        /// <param name="index">索引 System.Windows.Forms.TreeNode 中删除。</param>
        public virtual void RemoveAt(int index)
        {
            this.collection.RemoveAt(index);
        }

        /// <summary>
        /// 从集合中移除具有指定键的树节点。
        /// </summary>
        /// <param name="key">要从集合中移除的树节点的名称。</param>
        public virtual void RemoveByKey(string key)
        {
            TreeNode node = this[key];
            this.Remove(node);
        }

        int IList.Add(object value)
        {
            return this.Add((TreeNode)value);
        }

        bool IList.Contains(object value)
        {
            return this.Contains((TreeNode)value);
        }

        void ICollection.CopyTo(Array array, int index)
        {
            this.collection.CopyTo(array.OfType<TreeNode>().ToArray(), index);
        }

        int IList.IndexOf(object value)
        {
            return this.IndexOf((TreeNode)value);
        }

        void IList.Insert(int index, object value)
        {
            this.Insert(index, (TreeNode)value);
        }

        void IList.Remove(object value)
        {
            this.Remove((TreeNode)value);
        }
    }
}
